package application;

import zhengqc.list.ArrayList;
import zhengqc.stack.ArrayStack;
import zhengqc.stack.Stack;

public class Infix2Postfix {
    private char[] infix;
    private Stack<Character> operatorStack;
    private ArrayList<Character> postfix;
    private BracketsMatching bracketsMatching;
    private boolean valid;
    public Infix2Postfix() {
        this.operatorStack = new ArrayStack<>();
        this.postfix = new ArrayList<>();
        this.bracketsMatching = new BracketsMatching();
    }
    public void setInfix(String input) {
        this.infix = input.toCharArray();
        this.postfix.clear();
        this.operatorStack.clear();
        this.bracketsMatching.setBrackets(this.infix);
        this.valid = this.bracketsMatching.isValid();
    }
    public void setInfix(char[] input) {
        this.infix = input;
        this.postfix.clear();
        this.operatorStack.clear();
    }
    public boolean isValid() {
        return this.valid;
    }
    /* 暂且只能处理 + - * / */
    private int getOperatorPriority(char current) {
        switch (current) {
            case '+':
            case '-':
                return 1;
            case '*':
            case '/':
                return 2;
            default:
                return 0;
        }
    }
    private boolean isOperator(char current) {
        return this.getOperatorPriority(current) != 0;
    }
    /* 暂且只能处理 + - * / */
    private void processOperator(char currentOperator) {
        int currentOperatorPriority = this.getOperatorPriority(currentOperator);
        while (!this.operatorStack.isEmpty()) {
            char topOperator = this.operatorStack.peek();
            int topOperatorPriority = this.getOperatorPriority(topOperator);
            if (topOperatorPriority >= currentOperatorPriority) {
                this.postfix.addLast(this.operatorStack.pop());
            } else {
                break;
            }
        }
        this.operatorStack.push(currentOperator);
    }
    public ArrayList<Character> transform() {
        if (!this.valid) return null;
        for (char current: this.infix) {
            switch (current) {
                case '+':
                case '-':
                case '*':
                case '/':
                    this.processOperator(current);
                    break;
                case '(':
                    operatorStack.push(current);
                    break;
                case ')':
                    while (!operatorStack.isEmpty()) {
                        char topOperator = operatorStack.pop();
                        if (topOperator == '(') {
                            break;
                        } else {
                            postfix.addLast(topOperator);
                        }
                    }
                    break;
                default:
                    postfix.addLast(current);
                    break;
            }
        }
        while (!this.operatorStack.isEmpty()) {
            this.postfix.addLast(operatorStack.pop());
        }
        return this.postfix;
    }
    public Integer calculate() {
        if (!this.valid) return null;
        Stack<Integer> stack = new ArrayStack<>();
        for (int i = 0; i < this.postfix.getSize(); ++i) {
            char current = this.postfix.get(i);
            if (!isOperator(current)) {
                stack.push(Integer.parseInt(String.valueOf(current)));
            } else {
                int a = stack.pop();
                int b = stack.pop();
                if      (current == '+') stack.push(b + a);
                else if (current == '-') stack.push(b - a);
                else if (current == '*') stack.push(b * a);
                else if (current == '/') stack.push(b / a);
            }
        }
        return stack.pop();
    }
}
